package collectors;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

/**
 * @Classname Demo
 * @Description TODO
 * @Date 2023/4/23 22:00
 * @Created by guochen
 */
@Slf4j
public class Demo {

    List<Student> menu = Arrays.asList(
            new Student("刘一", 721, true, Student.GradeType.THREE),
            new Student("陈二", 637, true, Student.GradeType.THREE),
            new Student("张三", 666, true, Student.GradeType.THREE),
            new Student("李四", 531, true, Student.GradeType.TWO),
            new Student("王五", 483, false, Student.GradeType.THREE),
            new Student("赵六", 367, true, Student.GradeType.THREE),
            new Student("孙七", 499, false, Student.GradeType.ONE));


    @Test
    public void testAveragingDouble() {
        Double averagingDouble = menu.stream().collect(Collectors.averagingDouble(Student::getTotalScore));
        Optional.ofNullable(averagingDouble).ifPresent(System.out::println);
    }

    @Test
    public void testCollectingAndThen() {
        Optional.ofNullable(menu.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.averagingInt(Student::getTotalScore), a -> "The Average totalScore is->" + a)
        )).ifPresent(System.out::println);
    }

    // The Average totalScore is->557.7142857142857
    @Test
    public void testCounting() {
        Optional.of(menu.stream().collect(Collectors.counting())).ifPresent(System.out::println);
    }
// 7

    @Test
    public void testGroupingByFunction() {
        Map<Student.GradeType, List<Student>> collect = menu.stream()
                .collect(Collectors.groupingBy(Student::getGradeType));

        Optional.ofNullable(collect).ifPresent(System.out::println);
    }
// {TWO=[Student{name='李四', totalScore=531, local=true, gradeType=TWO}], THREE=[Student{name='刘一', totalScore=721, local=true, gradeType=THREE}, Student{name='陈二', totalScore=637, local=true, gradeType=THREE}, Student{name='张三', totalScore=666, local=true, gradeType=THREE}, Student{name='王五', totalScore=483, local=false, gradeType=THREE}, Student{name='赵六', totalScore=367, local=true, gradeType=THREE}], ONE=[Student{name='孙七', totalScore=499, local=false, gradeType=ONE}]}
@Test
public void testGroupingByFunctionAndCollector() {
    Optional.of(menu.stream()
            .collect(Collectors.groupingBy(Student::getGradeType, Collectors.counting())))
            .ifPresent(System.out::println);
}
// {THREE=5, ONE=1, TWO=1}
@Test
public void testGroupingByFunctionAndSupplierAndCollector() {
    Map<Student.GradeType, Double> map = menu.stream()
            .collect(Collectors.groupingBy(
                    Student::getGradeType,
                    TreeMap::new,
                    Collectors.averagingInt(Student::getTotalScore)));

    Optional.of(map.getClass()).ifPresent(System.out::println);
    Optional.of(map).ifPresent(System.out::println);
}
// class java.util.TreeMap
// {ONE=499.0, TWO=531.0, THREE=574.8}
@Test
public void testJoining() {
    Optional.of(menu.stream().map(Student::getName).collect(Collectors.joining()))
            .ifPresent(System.out::println);
}
// 刘一陈二张三李四王五赵六孙七
@Test
public void testJoiningWithDelimiter() {
    Optional.of(menu.stream().map(Student::getName).collect(Collectors.joining(",")))
            .ifPresent(System.out::println);
}
// 刘一,陈二,张三,李四,王五,赵六,孙七
@Test
public void testJoiningWithDelimiterAndPrefixAndSuffix() {
    Optional.of(menu.stream().map(Student::getName).collect(Collectors.joining(",", "Names[", "]")))
            .ifPresent(System.out::println);
}
// Names[刘一,陈二,张三,李四,王五,赵六,孙七]
@Test
public void testMapping() {
    Optional.of(menu.stream().collect(Collectors.mapping(Student::getName, Collectors.joining(","))))
            .ifPresent(System.out::println);
}
// 刘一,陈二,张三,李四,王五,赵六,孙七
@Test
public void testMaxBy() {
    menu.stream().collect(Collectors.maxBy(Comparator.comparingInt(Student::getTotalScore)))
            .ifPresent(System.out::println);
}
// Student{name='刘一', totalScore=721, local=true, gradeType=THREE}
@Test
public void testMinBy() {
    menu.stream().collect(Collectors.minBy(Comparator.comparingInt(Student::getTotalScore)))
            .ifPresent(System.out::println);
}
// Student{name='赵六', totalScore=367, local=true, gradeType=THREE}
@Test
public void testPartitioningByWithPredicate() {
    Map<Boolean, List<Student>> collect = menu.stream()
            .collect(Collectors.partitioningBy(Student::isLocal));
    Optional.of(collect).ifPresent(System.out::println);
}
// {false=[Student{name='王五', totalScore=483, local=false, gradeType=THREE}, Student{name='孙七', totalScore=499, local=false, gradeType=ONE}], true=[Student{name='刘一', totalScore=721, local=true, gradeType=THREE}, Student{name='陈二', totalScore=637, local=true, gradeType=THREE}, Student{name='张三', totalScore=666, local=true, gradeType=THREE}, Student{name='李四', totalScore=531, local=true, gradeType=TWO}, Student{name='赵六', totalScore=367, local=true, gradeType=THREE}]}
@Test
public void testPartitioningByWithPredicateAndCollector() {
    Map<Boolean, Double> collect = menu.stream()
            .collect(Collectors.partitioningBy(
                    Student::isLocal,
                    Collectors.averagingInt(Student::getTotalScore)));
    Optional.of(collect).ifPresent(System.out::println);
}
// {false=491.0, true=584.4}
@Test
public void testcollectBinaryOperator() {
    menu.stream().collect(Collectors
            .reducing(BinaryOperator
                    .maxBy(Comparator
                            .comparingInt(Student::getTotalScore))))
            .ifPresent(System.out::println);
}
// Student{name='刘一', totalScore=721, local=true, gradeType=THREE}
@Test
public void testReducingBinaryOperator() {
    menu.stream().reduce(BinaryOperator
            .maxBy(Comparator
                    .comparingInt(Student::getTotalScore)))
            .ifPresent(System.out::println);
}
// Student{name='刘一', totalScore=721, local=true, gradeType=THREE}
@Test
public void testSummarizingInt() {
    DoubleSummaryStatistics result = menu.stream()
            .collect(Collectors.summarizingDouble(Student::getTotalScore));
    Optional.of(result).ifPresent(System.out::println);
}
// DoubleSummaryStatistics{count=7, sum=3904.000000, min=367.000000, average=557.714286, max=721.000000}
// IntSummaryStatistics{count=7, sum=3904, min=367, average=557.714286, max=721}
// LongSummaryStatistics{count=7, sum=3904, min=367, average=557.714286, max=721}
@Test
public void testSummingDouble() {
    Optional.of(menu.stream().collect(Collectors.summingDouble(Student::getTotalScore)))
            .ifPresent(System.out::println);
}
// 3904.0
// 3904
// 3904
@Test
public void testToCollection() {
    Optional.of(menu.stream().filter(d -> d.getTotalScore() > 600)
            .collect(Collectors.toCollection(LinkedList::new)))
            .ifPresent(v -> {
                System.out.println(v.getClass());
                System.out.println(v);
            });
}
// class java.util.LinkedList
// [Student{name='刘一', totalScore=721, local=true, gradeType=THREE}, Student{name='陈二', totalScore=637, local=true, gradeType=THREE}, Student{name='张三', totalScore=666, local=true, gradeType=THREE}]
@Test
public void testToConcurrentMap() {
    Optional.of(menu.stream()
            .collect(Collectors.toConcurrentMap(Student::getName, Student::getTotalScore)))
            .ifPresent(v -> {
                System.out.println(v);
                System.out.println(v.getClass());
            });
}
// {李四=531, 孙七=499, 刘一=721, 张三=666, 陈二=637, 王五=483, 赵六=367}
// class java.util.concurrent.ConcurrentHashMap
    /**
     * GradeType:TotalNum
     */
    @Test
    public void testToConcurrentMapWithBinaryOperator() {
        Optional.of(menu.stream()
                .collect(Collectors.toConcurrentMap(Student::getGradeType, v -> 1L, (a, b) -> a + b)))
                .ifPresent(v -> {
                    System.out.println(v);
                    System.out.println(v.getClass());
                });
    }
// {ONE=1, THREE=5, TWO=1}
// class java.util.concurrent.ConcurrentHashMap
    /**
     * GradeType:TotalNum
     */
    @Test
    public void testToConcurrentMapWithBinaryOperatorAndSupplier() {
        Optional.of(menu.stream()
                .collect(Collectors.toConcurrentMap(
                        Student::getGradeType,
                        v -> 1L,
                        (a, b) -> a + b,
                        ConcurrentSkipListMap::new)))
                .ifPresent(v -> {
                    System.out.println(v);
                    System.out.println(v.getClass());
                });
    }
// {ONE=1, TWO=1, THREE=5}
// class java.util.concurrent.ConcurrentSkipListMap


    @Test
    public void testToSet() {
        Optional.of(menu.stream().filter(Student::isLocal).collect(Collectors.toSet()))
                .ifPresent(r -> {
                    System.out.println(r.getClass());
                    System.out.println(r);
                });
    }
// class java.util.HashSet
// [Student{name='张三', totalScore=666, local=true, gradeType=THREE}, Student{name='陈二', totalScore=637, local=true, gradeType=THREE}, Student{name='刘一', totalScore=721, local=true, gradeType=THREE}, Student{name='李四', totalScore=531, local=true, gradeType=TWO}, Student{name='赵六', totalScore=367, local=true, gradeType=THREE}]




















}
